﻿#include "Management.h"
#include <iostream>
#include <fstream> //文件流
#include <sstream> //字符串流
#include<algorithm> //算法
#include <string>

using namespace std;
bool status = true;

Management::Management() {
    //读取学生信息
    readFile("..\\info\\test1.txt");
    //加载背景图片
    ::loadimage(&m_bg, "..\\image\\bg.png", Window::width(), Window::height());
    //设置文字的大小，以改变格子的宽度和高度
    ::settextstyle(25, 0, "楷体");

    //主界面按钮初始化,push_back()在vector尾部加入一个数据
    menu_btns.push_back(new PushButton("点击以查看使用"));
    menu_btns.push_back(new PushButton("读取文件信息"));
    menu_btns.push_back(new PushButton("增加学生信息"));
    menu_btns.push_back(new PushButton("删除学生信息"));
    menu_btns.push_back(new PushButton("修改学生信息"));
    menu_btns.push_back(new PushButton("查找学生信息"));
    menu_btns.push_back(new PushButton("退出并保存信息"));

    for (int i = 0; i < menu_btns.size(); i++) {
        menu_btns[i]->setFixedSize(250, 50);
        //设置垂直间隔
        int vSpacing = (Window::height() - menu_btns.size() * menu_btns[i]->height()) - 50;
        //设置按钮位置居中
        int x1Pos = (Window::width() - menu_btns[i]->width()) / 2;
        int y1Pos = vSpacing + i * menu_btns[i]->height();
        menu_btns[i]->movePosition(x1Pos, y1Pos);
    }

    //初始化表格
    m_showTable = new Table;
    m_showTable->setRow(12);
    m_showTable->setHeader(m_headName);
    //设置表格居中
    m_showTable->movePosition(30, 100);
    //遍历将学生信息插入到表格
    for (auto &stuInfo:vec_stu) {
        m_showTable->insertData(stuInfo.formatInfo());
    }

    /*添加*/
    m_addEdit.setFixedSize(400, 30);
    m_addEdit.movePosition((Window::width() - m_addEdit.width()) / 2, (Window::height() - m_addEdit.height()) / 2);

    m_addBtn.setFixedSize(50, 30);
    m_addBtn.movePosition(m_addBtn.x() + m_addBtn.width() + 20, m_addBtn.y());
    m_addBtn.setBtnText("确定");

    /*删除*/
    delEdit = new LineEdit(0, 0, 200, 30);
    delEdit->setInputBoxTitle("请输入学生学号");

    delBtn = new PushButton("删除", 0, 0, 200, 30);

    delTable = new Table;
    delTable->setRow(6);
    delTable->setHeader(m_headName);

    //将编辑框，按钮和表格移动到指定位置
    delEdit->movePosition((Window::width() - (delEdit->width() * 2 + 20)) / 2, Window::height() / 3);
    delBtn->movePosition(delEdit->x() + delEdit->width() + 20, Window::height() / 3);
    delTable->movePosition((Window::width() - delTable->width()) / 2, Window::height() / 3 + 100);

    /*修改*/
    m_modifyEdit = new LineEdit(0, 0, 200, 30);
    m_modifyEdit->movePosition((Window::width() - m_modifyEdit->width()) / 2, Window::height() / 3);

    int width = 120;    //修改页表格宽度
    int w = width * 6;
    int vspace = (Window::width() - w) / 2; //水平间隔
    for (int i = 0; i < 6; i++) {
        m_stuEdits.push_back(new LineEdit(vspace + i * width, m_modifyEdit->y() + 120, width, 30));
        m_stuEdits[i]->setCursorHide(true);    //隐藏光标
    }

    m_stuEdits[0]->setInputBoxTitle("请输入学号:");
    m_stuEdits[1]->setInputBoxTitle("请输入姓名:");
    m_stuEdits[2]->setInputBoxTitle("请输入性别:");
    m_stuEdits[3]->setInputBoxTitle("请输入年龄:");
    m_stuEdits[4]->setInputBoxTitle("请输入专业:");
    m_stuEdits[5]->setInputBoxTitle("请输入班级:");

    /*查找*/
    searchEdit = new LineEdit(0, 0, 200, 30);
    searchIdBtn = new PushButton("按学号查找", 0, 0, 200, 30);
    searchNameBtn = new PushButton("按姓名查找", 0, 0, 200, 30);
    searchTable = new Table;
    searchTable->setRow(6);
    searchTable->setHeader(m_headName);

    //按学号查找按钮
    searchIdBtn->movePosition((Window::width() - searchIdBtn->width()) / 2, Window::height() / 4);
    //按姓名查找按钮
    searchNameBtn->movePosition((Window::width() - searchNameBtn->width()) / 2,
                                Window::height() / 4 + searchNameBtn->height());

    searchEdit->movePosition((Window::width() - searchEdit->width()) / 2, Window::height() / 3);
    searchTable->movePosition((Window::width() - searchTable->width()) / 2, Window::height() / 3 + 100);
}

void Management::help() {
    outtextxy(0, 30, "--帮助--");
    settextstyle(35, 0, "楷体");
    settextcolor(RED);
    char title1[20] = "操作说明:";
    char title2[50] = "1.按ESC键或鼠标右键来返回上一级。";
    char title3[100] = "2.点击读取文件信息可以输出指定文件的信息和查看增删改查";
    char title4[25] = "后的学生信息。";
    char title5[100] = "例如：在读取text1.txt文件信息后，在点击退出并保存学生";
    char title6[100] = "信息后会将新的学生信息保存在test2.txt。";

    outtextxy(100, 200, title1);
    outtextxy(100, 250, title2);
    outtextxy(100, 300, title3);
    outtextxy(80, 350, title4);
    outtextxy(100, 400, title5);
    outtextxy(80, 450, title6);

    settextstyle(25, 0, "楷体");
}

void Management::run() {
    /*解决闪屏，采用双缓冲绘图
     * Window::beginDraw()
     * Window::clear()
     * Window::flushDraw()
     * Window::endDraw*/
    Window::beginDraw();
    while (status) {
        Window::clear();
        drawBackground();
        //返回菜单
        if (Window::hashMsg()) {
            m_msg = Window::getMsg();
            switch (m_msg.message) {
                case WM_KEYDOWN: //按键按下
                    //按esc键退出,VK_ESCAPE 0x1B ESC 键
                    if (m_msg.vkcode == VK_ESCAPE) {
                        op = Menu;
                    }
                    break;

                case WM_RBUTTONDOWN:  //鼠标右键按下
                    op = Menu;
                    break;

                default: //鼠标左键按下
                    eventLoop();
                    break;
            }
        }

        outtextxy(0, 0, "系统状态:");

        switch (op) {
            case Menu:
                //获取菜单返回值
                op = menu();
                break;

            case Management::Help:
                help();
                break;

            case Management::Show:
                showStuInfo();
                break;

            case Management::Add:
                addStuInfo();
                break;

            case Management::Delete:
                deleteStuInfo();
                break;

            case Management::Modify:
                modifyStuInfo();
                break;

            case Management::Search:
                searchStuInfo();
                break;


            case Management::Exit:
                writeFile("..\\info\\test2.txt");
                exitSystem();
        }
        Window::flushDraw();
    }
    Window::endDraw();
}

int Management::menu() {
    //设置系统标题
    settextstyle(50, 0, "楷体");
    char title[50] = "学生信息管理系统";
    outtextxy((Window::width() - textwidth(title)) / 2, 50, title);
    //设置个人信息
    settextstyle(25, 0, "楷体");
    outtextxy(1010, 420, "xxxxxxxxx");
    outtextxy(1060, 460, "xxx");
    outtextxy(1060, 500, "  xxx");
    //加载功能菜单
    outtextxy(0, 30, "--菜单--");
    for (int i = 0; i < menu_btns.size(); i++) {
        menu_btns[i]->show();
        menu_btns[i]->eventLoop(m_msg);
        if (menu_btns[i]->isClicked()) {
            return i; //返回被点击的按钮下标
        }
    }
    return Menu;
}

void Management::showStuInfo() {
    outtextxy(0, 30, "--查看--");
    m_showTable->show();
}

void Management::addStuInfo() {
    outtextxy(0, 30, "--添加--");
    settextstyle(50, 0, "楷体");
    char title[50] = "--执行添加学生操作中--";
    outtextxy((Window::width() - textwidth(title)) / 2, 50, title);
    //设置输入框
    m_addEdit.show();
    //设置确定按钮效果
    settextstyle(25, 0, "楷体");
    m_addBtn.show();
    m_addBtn.setFixedSize(70, 40);
    m_addBtn.movePosition(m_addEdit.x() + 450, m_addEdit.y());
    //设置提示文本
    outtextxy(m_addEdit.x() - 150, m_addEdit.y() - 150, "请输入需要添加的学生信息(学号 姓名 性别 年龄 专业 班级)");


    if (m_addBtn.isClicked() && Timer::startTimer(200, 0)) {
        std::string newData = m_addEdit.text();
        //如果输入学生数据为空或输入的学生信息不全
        if (newData.empty() || std::count(newData.begin(), newData.end(), ' ') != 5/*根据空格数来判断是否填全信息*/) {
            printf("添加失败，可能是无学生信息或学生信息不全或没有按照规定格式输入\n");
            return;
        }

        //格式化数据 replace ：将范围内的所有等于 old_value 的元素都用 new_value 替代
        std::replace(newData.begin(), newData.end(), ' ', '\t'); //将空格转化为'\t'，方便之后将其放入表格
        //先数据放入动态数组m_data中暂存
        m_showTable->insertData(newData);
        Student t;
        //把数据转为字符串
        t.formatWrite(newData);
        vec_stu.push_back(t);
        //清除编辑框的文字
        m_addEdit.clear();

        printf("添加成功！\n");
        updateTableData();
    }
}

void Management::deleteStuInfo() {
    outtextxy(0, 30, "--删除--");
    settextstyle(50, 0, "楷体");
    char title[50] = "--执行删除学生操作中--";
    outtextxy((Window::width() - textwidth(title)) / 2, 50, title);
    settextstyle(25, 0, "楷体");
    //设置提示文本
    outtextxy(delEdit->x(), delEdit->y() - 100, "请输入需要删除的学生学号:");

    delEdit->show(); //绘制删除编辑框
    delBtn->show(); //绘制删除按钮
    delTable->show(); //用Table展现出要删除的数据

    //学生类的迭代器，获取其末尾元素再下一个元素的迭代器
    static std::vector<Student>::iterator delIt = vec_stu.end();

    if (delEdit->textChanged()) {
        std::string info = delEdit->text();
        if (info.empty()) return;

        Student stu;
        stringstream stream(info);
        stream >> stu.Sno;
        delIt = std::find(vec_stu.begin(), vec_stu.end(), stu);
        if (delIt != vec_stu.end()) {
            delTable->insertData(delIt->formatInfo());
        }
    }

    //删除按钮按下
    if (delBtn->isClicked() && delIt != vec_stu.end() && Timer::startTimer(200, 1)) {
        //清除编辑框的数据
        delEdit->clear();
        std::cout << "删除成功！" << std::endl;
        vec_stu.erase(delIt); //去除delit
        delTable->clearTableData();
        delIt = vec_stu.end(); //跳出循环

        updateTableData();
    }
}

void Management::modifyStuInfo() {
    outtextxy(0, 30, "--修改--");
    settextstyle(50, 0, "楷体");
    char title[50] = "--执行修改学生操作中--";
    outtextxy((Window::width() - textwidth(title)) / 2, 50, title);
    settextstyle(25, 0, "楷体");

    m_modifyEdit->show();
    for (int i = 0; i < 6; i++) {
        m_stuEdits[i]->show();
    }

    settextstyle(30, 0, "楷体");
    outtextxy(m_modifyEdit->x() - 80, m_modifyEdit->y() - 80, "请输入需要修改的学生学号:");


    if (m_modifyEdit->textChanged()) {
        std::string res = m_modifyEdit->text();
        Student stu;
        std::stringstream stream(res);
        stream >> stu.Sno;

        auto findIt = std::find(vec_stu.begin(), vec_stu.end(), stu);

        if (findIt != vec_stu.end()) {
            m_modifyIt = findIt;
            haveStu = true;
            cout << "待修改的学生信息: ";

            m_stuEdits[0]->setText(to_string(findIt->Sno));
            m_stuEdits[1]->setText(findIt->Sname);
            m_stuEdits[2]->setText(findIt->Ssex);
            m_stuEdits[3]->setText(to_string(findIt->Sage));
            m_stuEdits[4]->setText(findIt->Sdept);
            m_stuEdits[5]->setText(findIt->Sclass);

            findIt->show();

        } else {
            haveStu = false;
        }
    }

    //如果修改了学生信息
    if (haveStu) {
        for (int i = 0; i < 6; i++) {
            if (m_stuEdits[i]->textChanged()) {
                switch (i) {
                    case 0:        //修改学号
                        m_modifyIt->Sno = atoi(m_stuEdits[i]->text().data()); //atoi函数将字符串转换成整型数
                        break;
                    case 1:        //修改姓名
                        m_modifyIt->Sname = m_stuEdits[i]->text();
                        break;
                    case 2:        //修改性别
                        m_modifyIt->Ssex = m_stuEdits[i]->text();
                        break;
                    case 3:        //修改年龄
                        m_modifyIt->Sage = atoi(m_stuEdits[i]->text().data());
                        break;
                    case 4:        //修改专业
                        m_modifyIt->Sdept = m_stuEdits[i]->text();
                        break;
                    case 5:        //修改班级
                        m_modifyIt->Sclass = m_stuEdits[i]->text();
                        break;
                }
                updateTableData();
            }
        }
    } else {
        settextstyle(18, 0, "楷体");
        setfillcolor(RGB(194, 195, 201));
        solidrectangle(m_stuEdits[0]->x(), m_stuEdits[0]->y(), m_stuEdits[0]->x() + 6 * 120, m_stuEdits[0]->y() + 30);
        outtextxy(m_stuEdits[0]->x(), m_stuEdits[0]->y() + 5, "请在上方输入框中输入要查找的学生学号，然后点击此处信息直接编辑");
    }
}

void Management::searchStuInfo() {
    outtextxy(0, 30, "--查找--");
    settextstyle(50, 0, "楷体");
    char title[50] = "--执行查找学生操作中--";
    outtextxy((Window::width() - textwidth(title)) / 2, 50, title);
    settextstyle(25, 0, "楷体");

    int where = -1;        //记录时按学号查找还是按姓名查找
    if (searchIdBtn->isClicked()) {
        std::cout << "开始学号查询" << std::endl;
        searchEdit->setInputBoxTitle("请输入学号:");
        searchEdit->popInputBox();
        where = 0;
    }
    if (searchNameBtn->isClicked()) {
        std::cout << "开始姓名查询" << std::endl;
        searchEdit->setInputBoxTitle("请输入姓名:");
        searchEdit->popInputBox();
        where = 1;
    }

    searchIdBtn->show();
    searchNameBtn->show();
    searchTable->show();


    std::string res = searchEdit->text();
    if (!res.empty()) {
        Student stu;
        std::stringstream stream(res);
        if (where == 0) { /*学号*/
            stream >> stu.Sno;
            auto findIt = std::find(vec_stu.begin(), vec_stu.end(), stu);
            if (findIt != vec_stu.end()) {
                cout << "已通过学号找到目的学生信息：";
                searchTable->insertData(findIt->formatInfo());
                findIt->show();
            }
        } else if (where == 1) { /*姓名*/
            stream >> stu.Sname;
            for (Student &s : vec_stu) {
                if (s.Sname == stu.Sname) {
                    cout << "已通过姓名找到目的学生信息：";
                    searchTable->insertData(s.formatInfo());
                    s.show();
                }
            }
        }
    }
}

void Management::exitSystem() {
    cout << "Tip:---学生信息管理系统已安全退出，谢谢使用！---" << endl;
    exit(0);
}

void Management::drawBackground() {
    //绘制背景图片
    ::putimage(0, 0, &m_bg);
}

void Management::readFile(const string &fileName) {
    fstream read(fileName, ios::in); //ios::in 读 文件不存在 就无法打开
    if (!read.is_open()) {
        return;
    }
    //读取文件表头
    char buf[1024] = {0};
    read.getline(buf, 1024); //使用getline()函数读取每行的数据
    m_headName = buf;
    //    cout << m_headName << endl;

    //    读取文件学生信息
    while (!read.eof()) { //使用eof()函数来判断是否读到文件末尾
        char data[1024] = {0};
        read.getline(data, 1024);
        //跳过空行
        if (strlen(data) == 0) {
            break;
        }
        Student stu;
        stringstream ss(data); //stringstream进行流的输入输出操作
        ss >> stu.Sno >> stu.Sname >> stu.Ssex >> stu.Sage >> stu.Sdept >> stu.Sclass;
        vec_stu.push_back(stu); //push_back在vector尾部加入一个数据
        //        cout << stu.Sno << stu.Sname << stu.Ssex << stu.Sage << stu.Sdept << stu.Sclass << endl;
    }
    read.close();
}

void Management::writeFile(const string &fileName) {
    fstream write(fileName, ios::trunc | ios::out); /*写 trunc:将先前的文件内容移除*/
    if (!write.is_open()) {
        cerr << fileName << "file open failed" << endl; //cerr输出错误信息与其他不属于正常逻辑的输出内容
        return;
    }
    //写表头
    m_headName += "\n";
    write.write(m_headName.c_str(), m_headName.size());
    //写信息
    for (auto &stuInfo:vec_stu) {
        std::string info = stuInfo.formatInfo();
        write.write(info.c_str(), info.size());
    }
    write.close();
}

void Management::eventLoop() {
    if (op == Show) {
        m_showTable->eventTableLoop(m_msg);

    } else if (op == Add) {
        m_addBtn.eventLoop(m_msg);
        m_addEdit.eventLoop(m_msg);

    } else if (op == Delete) {
        delBtn->eventLoop(m_msg);
        delEdit->eventLoop(m_msg);

    } else if (op == Modify) {
        m_modifyEdit->eventLoop(m_msg);
        if (haveStu) {
            for (int i = 0; i < 6; i++) {
                m_stuEdits[i]->eventLoop(m_msg);
            }
        }

    } else if (op == Search) {
        searchIdBtn->eventLoop(m_msg);
        searchNameBtn->eventLoop(m_msg);
        searchEdit->eventLoop(m_msg);
    }
}

void Management::updateTableData() {
    m_showTable->clearTableData();
    for (auto val : vec_stu) {
        m_showTable->insertData(val.formatInfo());
    }
}














